package cim144.digital

import Chisel._
import freechips.rocketchip.config._
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.tile._ // LazyModule

object MAC {
    def apply(in1:UInt,in2:UInt):UInt={
        val inst = Module(new MAC()).io
        inst.in1 := in1
        inst.in2 := in2
        inst.out
    }
}

class MAC(val w : Int = 64) extends Module{
    val io = IO(new Bundle{
        val in1 = Input(UInt(w.W))
        val in2 = Input(UInt(w.W))
        val out = Output(UInt(w.W))
    })
    val x = io.in1.asTypeOf(Vec(8,SInt(8.W)))
    val y = io.in2.asTypeOf(Vec(8,SInt(8.W)))
    val result_tmp = Wire(SInt(64.W))
    result_tmp  := x.zip(y).map{case (t,t1)=> t*t1 }.reduce(_+_)
    io.out := result_tmp.asUInt()
}


class MAC8bit(opcodes: OpcodeSet)(implicit p: Parameters) extends LazyRoCC(opcodes){
    override lazy val module = new LazyRoCCModuleImp(this){//
        // LazyRoCCModuleImp predefine IO
        val rd          = RegInit(0.U(5.W))
        val rs1Value    = RegInit(0.U(64.W))
        val Enable      = RegInit(false.B)
        val rs2Value    = RegInit(0.U(64.W))
        val rdValid     = RegInit(false.B)

        val busy = RegInit(false.B)
        io.cmd.ready := !busy
        io.busy := busy
        //**********custom1 function=1**********//
        val canDecode = io.cmd.valid && (io.cmd.bits.inst.funct===1.U)
        when(canDecode){ // 
            busy     := true.B
            rs1Value := io.cmd.bits.rs1
            Enable   := true.B
            rs2Value := io.cmd.bits.rs2
            rd       := io.cmd.bits.inst.rd
        }
        when(Enable){
            rdValid  := true.B
        }
        val macres = MAC(rs1Value,rs2Value)

        io.resp.valid := rdValid
        io.resp.bits.rd := rd
        io.resp.bits.data := macres
        when(io.resp.fire()){
            busy     := false.B
            Enable   := false.B
            rs1Value := 0.U
            rs2Value := 0.U
            rdValid  := 0.U
        }  
       
    }
}

class WithMAC extends Config((site,here,up) => {
    case BuildRoCC => Seq(       
        (p:Parameters) => {
            val MAC8bit = LazyModule(new MAC8bit(OpcodeSet.custom1)(p))
            MAC8bit
        }
    )
})